package com.xiaojian.blog.controller;

import com.github.pagehelper.PageInfo;
import com.sun.javaws.security.Resource;
import com.vdurmont.emoji.EmojiParser;
import com.xiaojian.blog.constant.WebConstant;
import com.xiaojian.blog.dto.ErrorCode;
import com.xiaojian.blog.dto.Types;
import com.xiaojian.blog.model.CommentPO;
import com.xiaojian.blog.model.ContentPO;
import com.xiaojian.blog.model.MetaPO;
import com.xiaojian.blog.model.VO.ArchiveVO;
import com.xiaojian.blog.model.VO.CommentVO;
import com.xiaojian.blog.model.VO.RestResponseVO;
import com.xiaojian.blog.service.CommentService;
import com.xiaojian.blog.service.ContentService;
import com.xiaojian.blog.service.MetaService;
import com.xiaojian.blog.service.SiteService;
import com.xiaojian.blog.utils.IPKit;
import com.xiaojian.blog.utils.PatternKit;
import com.xiaojian.blog.utils.TaleUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.lang.model.element.NestingKind;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.websocket.server.PathParam;
import java.net.URLEncoder;
import java.util.List;


/**
 * 首页控制器
 */
@Controller
public class IndexController extends BaseController {

    @Autowired
    private CommentService commentService;

    @Autowired
    private SiteService siteService;

    @Autowired
    private ContentService contentService;

    @Autowired
    private MetaService metaService;



    private static final Logger LOGGER = LoggerFactory.getLogger(IndexController.class);

    @GetMapping(value = "/")
    public String index(HttpServletRequest request,
                        @RequestParam(value = "limit", defaultValue = "12") int limit) {
        return this.index(request, 1, limit);
    }

    /**
     * 首页分页的方法
     * @param request 请求体
     * @param p 第几页
     * @param limit 每页数量
     * @return  主页
     */
    @GetMapping(value = "page/{p}")
    public String index(HttpServletRequest request,
                        @PathVariable int p,
                        @RequestParam(value = "limit", defaultValue = "12") int limit) {

        p = p < 0 || p > WebConstant.MAX_PAGE ? 1 : p;
        PageInfo<ContentPO> contents = contentService.getContents(p, limit);
        request.setAttribute("articles", contents);
        if (p > 1) {
            this.title(request, "第" + p + "页");
        }
        return this.render("index");
    }

    /**
     * 文章页,查看某个文章详情
     * @param request 请求
     * @param cid 文章的主键
     * @return
     */
    @GetMapping(value = {"article/{cid}", "article/{cid}.html"})
    public String getArticle(HttpServletRequest request,
                             @PathVariable String cid) {
        ContentPO contentPO = contentService.getContents(cid);
        if (null == contentPO || "draft".equals(contentPO.getStatus())) {
            return this.render_404();
        }
        request.setAttribute("article", contentPO);
        request.setAttribute("is_post", true);
        completeArticle(request, contentPO);
        //校验是否是重复阅读同一篇文章
        if (!checkHitsFrequency(request, cid)) {
            //不是,则更新文章点击次数
            updateArticleHit(contentPO.getCid(), contentPO.getHits());
        }
        return this.render("post");

    }

    @GetMapping(value = {"article/{cid}/preview", "article/{cid}.html"})
    public String articlePreview(HttpServletRequest request, @PathVariable String cid) {
        ContentPO content = contentService.getContents(cid);
        if (null == content) {
            return this.render_404();
        }
        request.setAttribute("article", content);
        request.setAttribute("is_post", true);
        //获取文章的评论
        completeArticle(request, content);
        if (!checkHitsFrequency(request, cid)) {
            updateArticleHit(content.getCid(), content.getHits());
        }
        return this.render("post");
    }

    /**
     * 用户注销的方法
     */
    @RequestMapping("logout")
    public void logout(HttpSession session, HttpServletResponse response) {
        TaleUtils.logout(session, response);
    }



    /**
     * 评论操作
     */
    @PostMapping(value = "comment")
    @ResponseBody
    public RestResponseVO comment(HttpServletRequest request,
                                  HttpServletResponse response,
                                  @RequestParam Integer cid,
                                  @RequestParam Integer coid,
                                  @RequestParam String author,
                                  @RequestParam String mail,
                                  @RequestParam String url,
                                  @RequestParam String text,
                                  @RequestParam String _csrf_token) {
        String ref = request.getHeader("Referer");
        if (StringUtils.isBlank(ref) || StringUtils.isBlank(_csrf_token)) {
            return RestResponseVO.fail(ErrorCode.BAD_REQUEST);
        }
        String token = cache.hget(Types.CSRF_TOKEN.getType(), _csrf_token);
        if (StringUtils.isBlank(token)) {
            return RestResponseVO.fail(ErrorCode.BAD_REQUEST);
        }
        if (null == cid || StringUtils.isBlank(text)) {
            return RestResponseVO.fail("请输入完整后评论");
        }
        if (StringUtils.isNotBlank(author) && author.length() > 50) {
            return RestResponseVO.fail("姓名过长");
        }
        if (StringUtils.isNotBlank(mail) && !TaleUtils.isEmail(mail)) {
            return RestResponseVO.fail("请输入正确的邮箱格式");
        }
        if (StringUtils.isNotBlank(url) && !PatternKit.isURL(url)) {
            return RestResponseVO.fail("请输入正确的URL");
        }
        if (text.length() > 200) {
            return RestResponseVO.fail("请输入200个字符以内的评论");
        }
        //同一个IP发表评论不能太快
        String val = IPKit.getIpAddrByRequest(request) + ":" + cid;
        Integer count = cache.hget(Types.COMMENTS_FREQUENCY.getType(), val);
        if (null != count && count > 0) {
            return RestResponseVO.fail("您发表评论太快了,请稍后再试!");
        }
        //猜测应该是取出内容和作者中的xss注入的xml标签
        author = TaleUtils.cleanXSS(author);
        text = TaleUtils.cleanXSS(text);

        //表情的处理
        author = EmojiParser.parseToAliases(author);
        text = EmojiParser.parseToAliases(text);

        CommentPO  commentPO = new CommentPO();
        commentPO.setAuthor(author);
        commentPO.setCid(cid);
        commentPO.setIp(request.getRemoteAddr());
        commentPO.setUrl(url);
        commentPO.setContent(text);
        commentPO.setMail(mail);
        commentPO.setParent(coid);
        try {
            String result = commentService.insertComment(commentPO);
            cookie("tale_remember_author", URLEncoder.encode(author, "UTF-8"), 7 * 24 * 60 * 60, response);
            cookie("tale_remember_mail", URLEncoder.encode(mail, "UTF-8"), 7 * 24 * 60 * 60, response);
            if (StringUtils.isNotBlank(url)) {
                cookie("tale_remember_url", URLEncoder.encode(url, "UTF-8"),
                        7 * 24 * 60 * 60, response);
            }
            //设置对每个文章1分钟可以评论一次
            cache.hset(Types.COMMENTS_FREQUENCY.getType(), val, 1, 60);
            if (!WebConstant.SUCCESS_RESULT.equals(result)) {
                return RestResponseVO.fail(result);
            }
            return RestResponseVO.ok();
        }catch (Exception e) {
            String msg = "评论发布失败";
            LOGGER.error(msg, e);
            return RestResponseVO.fail(msg);
        }
    }

    /**
     * 归档
     */
    @GetMapping(value = "archives")
    public String archives(HttpServletRequest request) {
        List<ArchiveVO> archives = siteService.getArchives();
        request.setAttribute("archives", archives);
        return this.render("archives");
    }

    /**
     * 友链
     */
    @GetMapping(value = "links")
    public String links(HttpServletRequest request) {
        List<MetaPO> links = metaService.getMetas(Types.LINK.getType());
        request.setAttribute("links", links);
        return this.render("links");
    }

    /**
     * 自定义的页面,如关于页面
     */
    @GetMapping(value = "/{pagename}")
    public String page(@PathVariable String pagename, HttpServletRequest request) {
        ContentPO contentPO = contentService.getContents(pagename);
        if (null == contentPO) {
            return this.render_404();
        }
        if (contentPO.getAllowComment()) {
            String cp = request.getParameter("cp");
            if (StringUtils.isBlank(cp)) {
                cp = "1";
            }
            PageInfo<CommentVO> comments = commentService.getComments(contentPO.getCid(), Integer.parseInt(cp), 6);
            request.setAttribute("comments", comments);
        }
        request.setAttribute("article", contentPO);
        if (!checkHitsFrequency(request, String.valueOf(contentPO.getCid()))) {
            updateArticleHit(contentPO.getCid(), contentPO.getHits());
        }
        return this.render("page");
    }

    /**
     * 搜索页
     */
    @GetMapping(value = "search/{keyword}")
    public String search(HttpServletRequest request,
                         @PathVariable String keyword,
                         @RequestParam(value = "limit", defaultValue = "12") int limit) {
        return this.search(request, keyword, 1, limit);
    }

    @GetMapping(value = "search/{keyword}/{page}")
    public String search(HttpServletRequest request,
                         @PathVariable String keyword,
                         @PathVariable int page,
                         @RequestParam(value = "limit",defaultValue = "12") int limit) {
        page = page < 0 || page > WebConstant.MAX_PAGE ? 1 : page;
        PageInfo<ContentPO> articles = contentService.getArticles(keyword, page, limit);
        request.setAttribute("articles", articles);
        request.setAttribute("type", "搜索");
        request.setAttribute("keyword", keyword);
        return this.render("page-category");
    }

    /**
     * 抽取公共方法
     */
    private void completeArticle(HttpServletRequest request, ContentPO contentPO) {
        if (contentPO.getAllowComment()) {//判断文章是否允许评论
            String cp = request.getParameter("cp");
            if (StringUtils.isBlank(cp)) {
                cp = "1";
            }
            request.setAttribute("cp", cp);
            //获取所有的文章评论
            PageInfo<CommentVO> comments = commentService.getComments(contentPO.getCid(), Integer.parseInt(cp), 6);
            request.setAttribute("comments", comments);
        }
    }

    /**
     * 检查同一个ip地址是否在2小时内访问同一文章
     */
    private boolean checkHitsFrequency(HttpServletRequest request, String cid) {
        String val = IPKit.getIpAddrByRequest(request) + ":" + cid;
        Integer count = cache.hget(Types.HITS_FREQUENCY.getType(), val);
        if (null != count && count > 0) {
            //说明重复点击
            return true;
        }
        cache.hset(Types.HITS_FREQUENCY.getType(), val, 1, WebConstant.HITS_LIMIT_TIME);
        return false;
    }

    /**
     * 更新文章的点击率
     */
    private void updateArticleHit(Integer cid, Integer chits) {
        //首先从缓存容器中获取文章点击率
        Integer hits = cache.hget("article" + cid, "hits");
        if (chits == null) {
            chits = 0;
        }
        hits = null == hits ? 1 : hits + 1;
        if (hits >= WebConstant.HIT_EXCEED) {
            ContentPO contentPO = new ContentPO();
            contentPO.setCid(cid);
            contentPO.setHits(chits + hits);
            contentService.updateContentByCid(contentPO);
            cache.hset("article" + cid, "hits", 1);
        }else {
            cache.hset("article" + cid, "hits", hits);
        }
    }


    /**
     * 设置cookie的方法
     */
    private void cookie(String name, String value, int maxAge, HttpServletResponse response) {
        Cookie cookie = new Cookie(name, value);
        cookie.setMaxAge(maxAge);
        cookie.setSecure(false);
        response.addCookie(cookie);
    }
}
